package net.jueb.protoServer.handler.dispatcher;

import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;

import net.jueb.protoServer.controller.DefaultServiceController;
import net.jueb.protoServer.controller.ServiceController;
import net.jueb.protoServer.message.mapping.MessageMapping;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;

/**
 * 端口消息分发器,负责将消息分发到对应控制器处理方法
 * 该类默认把消息ID和有相同ID的控制器进行映射
 * 如果没有配置消息映射器或者没有匹配到,则创建一个默认消息处理控制器处理消息
 * @author Administrator
 * @param <M> 消息类型
 */
public class MessageDispatcherHandler<M> extends SimpleChannelInboundHandler<M>{
	protected static final InternalLogger log = InternalLoggerFactory.getInstance(MessageDispatcherHandler.class);
	protected final ConcurrentHashMap<Integer,ServiceController<?>> controllers;
	private MessageMapping<M> mapping;
	private ServiceController<Object> defaultServiceController;
	
	
	
	/**
	 * @param port 处理消息分发的端口
	 * @param dispatcherName 分发器名称
	 * @param controllers 该端口使用的消息处理控制器集合<消息ID,消息ID对应控制器>
	 * @param mapping 消息映射器
	 */
	public MessageDispatcherHandler(ConcurrentHashMap<Integer,ServiceController<?>> controllers) 
	{
		this.controllers=controllers;
	}
	
	/**
	 * 设置默认处理控制器，即消息没有正确映射器到控制器的时候，
	 * 如果没有设置，则默认使用DefaultServiceController
	 * @param controller
	 */
	public final void setDefaultServiceController(ServiceController<Object> controller)
	{
		this.defaultServiceController=controller;
	}
	
	public final ServiceController<?> getDefaultServiceController()
	{
		return this.defaultServiceController;
	}
	
	public final MessageDispatcherHandler<M> setMapping(MessageMapping<M> mapping)
	{
		this.mapping=mapping;
		return this;
	}
	
	public final MessageMapping<M> getMapping()
	{
		return this.mapping;
	}
	
	
	/**
	 * 该方法不允许被子类修改
	 */
	@Override
	protected final void channelRead0(ChannelHandlerContext ctx, M msg)throws Exception {
		if(msg==null)
		{
			log.debug("Message is null!");
			return ;
		}
		
		if(controllers==null && controllers.size()<=0)
		{
			log.warn("没有配置处理控制器!");
			return ;
		}
		if(mapping==null)
		{
			log.warn("没有配置消息映射器!");
			return ;
		}
		@SuppressWarnings("rawtypes")
		ServiceController controller=mappingControllerById(msg);//使用ID匹配
		if(controller==null)
		{//如果使用控制器ID没有匹配到则进行自定义规则匹配
			controller=mappingController(msg);
		}
		if(controller!=null)
		{//如果匹配到
			executeController(ctx, msg, controller);
		}else
		{//如果都没有匹配到,则调用默认控制器
			if(defaultServiceController==null)
			{
				defaultServiceController=new DefaultServiceController();
			}
			log.debug("未匹配控制器消息交由默认控制器:"+defaultServiceController.getControllerName()+"处理");
			executeDefaultController(ctx, msg, controller);
		}
	}
	
	/**
	 * 根据映射器的cid匹配规则找到控制器
	 * @param msg
	 * @return
	 */
	private ServiceController<?> mappingControllerById(M msg)
	{
		int cid=mapping.getControllerIdByMsg(msg);
		if(controllers.containsKey(cid))
		{
			ServiceController<?> controller=controllers.get(cid);
			if(controller!=null && controller.getId()==cid)
			{//如果控制器不为空,且消息ID匹配则调用该控制器处理消息
				log.debug("找到对应消息ID的服务处理控制器!");
				return controller;
			}else
			{
				log.debug("没有根据消息cid找到控制器");
				return null;
			}
		}
		return null;
	}
	
	/**
	 * 根据映射器的自定义匹配规则来获取消息对应控制器
	 * @param msg
	 * @return
	 */
	private ServiceController<?> mappingController(M msg)
	{
		Iterator<ServiceController<?>> it=controllers.values().iterator();
		while(it.hasNext())
		{
			ServiceController<?> controller=it.next();
			if(controller!=null && mapping.isMatch(msg, controller))
			{
				return controller;
			}
		}
		return null;
	}
	
	/**
	 * 成功匹配到控制器后
	 * 调用消息映射的控制器的执行方法
	 * @param ctx
	 * @param msg
	 * @param controller
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	protected void executeController(ChannelHandlerContext ctx, M msg,@SuppressWarnings("rawtypes") ServiceController controller) throws Exception
	{
		controller.execute(ctx, msg);
	}
	@SuppressWarnings("unchecked")
	protected void executeDefaultController(ChannelHandlerContext ctx, M msg,@SuppressWarnings("rawtypes") ServiceController controller)throws Exception
	{
		controller.execute(ctx, msg);
	}
}
